{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# チュートリアル プライバシーに配慮したディープラーニングの基本ツール\n",
    "\n",
    "プライバシーに配慮したディープラーニングを実現するPySyftの入門チュートリアルへようこそ。\n",
    "\n",
    "このJupyter notebooksのシリーズでは、機密や個人情報を含むデータやモデルを、一つの権限の元で一元管理するのではなく、権限的にも物理的にも分散した状態で実行するための、新しいツールやテクニックについて、一つ一つ順を追って説明していきます\n",
    "\n",
    "**適用範囲:**\n",
    "私たちはデータを分散化、暗号化する方法についてだけ扱うわけではありません。PySyftを使うことで、どうすれば各所に分散して配置されたデータを検索できるのか、一つのサーバーに集めずにデータを分散させたままにモデルの学習を行うにはどうすれば良いのか、モデル所有者とデータ所有者がそれぞれの知財を守りつつ連携した新しいサービスを生み出すにはそうすれば良いのか、といった新しいデータのエコシステム全体についての事柄を含みます。また、新しい拡張昨日がPySyftに追加された際には本Jupyter notebooksシリーズも同様に拡張されます。\n",
    "\n",
    "著者:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "\n",
    "\n",
    "## 概要:\n",
    "\n",
    "- パート 1: プライベート ディープラーニングを実現する基本ツール\n",
    "\n",
    "\n",
    "## このチュートリアルで学習する理由\n",
    "\n",
    "\n",
    "**1) キャリアアップ** - この20年間、デジタル革命によってデータのデジタル化が進み、より多くのデータがアクセス可能になりました。しかし、[GDPR](https://eugdpr.org/)に代表される新しい規制により、企業が自由に個人情報を分析、活用することは難しくなってきています。**ボトムライン** データサイエンティストも、昔ながらの手法では以前のようにはデータにアクセスできなくなります。しかし、個人情報に配慮したディープラーニングの手法を学ぶ事で、規制に従いつつデータにアクセスできるノウハウを身につけることができれば、このトレンドの先を行くことできます。あなたのキャリアにおいてもきっと強みとなるでしょう。\n",
    "\n",
    "**2) スタートアップのチャンス** - ディープラーニングを解決できる社会の問題はまだまだ沢山あります。しかしながら、その多くは、特に最も重要な問題の多くは、デリケートな**個人**に関する情報へのアクセスを要するため、まだ十分に探究されていません。プライバシーに配慮したディープラーニングを学ぶ事で、従来の手法ではアクセス出来ないデータ、例えば心の問題や男女の問題に関するデータ、がアクセス可能になると想像してみてください。新たなビジネスチャンスが広がると思いませんか。\n",
    "\n",
    "**3) 社会的意義** - ディープラーニングは現実世界の様々な問題を解決しうる技術です。個人の情報を扱うディープラーニングは個人の問題を、そうです、個人の問題を解決します。自分が所有していないデータを使ってディープラーニングのモデルを学習できる手法を学ぶことには、個人のキャリアアップやスタートアップ企業操業のチャンス以上の可能性があります。人々の営みにおけるもっとも重要な問題を解決できる、それを大規模にできる、そんな可能性を秘めているんです。\n",
    "\n",
    "## 貢献の方法は様々です\n",
    "- PySyftのGitHubレポジトリに星をつけてみる! - [https://github.com/OpenMined/PySyft](https://github.com/OpenMined/PySyft)\n",
    "- チュートリアルビデオをYoutubeで公開してみる!\n",
    "\n",
    "等々... では、はじましょう！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part -1: 前提となる知識\n",
    "\n",
    "- PyTorchに関する知識 - Pytorch初心者の方は http://fast.ai のコースに目を通しましょう。\n",
    "- PySyftの概要に興味のある方は\"PySyft Framework\"の論文に目を通しましょう https://arxiv.org/pdf/1811.04017.pdf! 論文を読むことで、PySyftがどのように設計されているのかについての背景知識が得られ、理にかなっている事もご納得いただけると思います。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 0: セットアップ\n",
    "\n",
    "まずは、正しいソフトウェアがインストールされていることを確認しましょう。PySyftのreadmeの指示にしたがってインストールを進めてください。\n",
    "\n",
    "- Install Python 3.6 or higher\n",
    "- Install PyTorch 1.4\n",
    "- pip install syft[udacity]\n",
    "\n",
    "もし、どこかしらで、つまづいてしまった時は、まずは[README](https://github.com/OpenMined/PySyft.git)をチェックしてください。それでも解決策が見つからない場合は、GithubでIssueを挙げてみるか、slackの#beginner channel　[slack.openmined.org](http://slack.openmined.org/)　で質問をしてみてください。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 以下のコードを実行して、必要なソフトウェアが正しくインストールされているか確認します\n",
    "import sys\n",
    "\n",
    "import torch\n",
    "from torch.nn import Parameter\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(torch)\n",
    "\n",
    "torch.tensor([1,2,3,4,5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "このセルが実行できていれば、準備はOKです。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 1: プライバシーに配慮したデータサイエンスの基本ツール\n",
    "\n",
    "- 自分がアクセスできないデータでモデルを学習させるなんて、いったい全体どうやるんだ？って思われるかもしれません。\n",
    "\n",
    "でも、答はビックリするくらい簡単です。Pytorchを良くご存知の方であれば、Torchオブジェクトはお馴染みだと思います。 \n",
    "\n",
    "例えば、こんな風に..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = x + x\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tensorオブジェクトとそのオペレーションはとても良くできていて、パワフルですが、データはあなたのマシンに存在している必要がありますよね。\n",
    "\n",
    "さて、ここが出発点です。\n",
    "\n",
    "# Section 1.1 - TensorをBobのマシンへ送る\n",
    "\n",
    "データサイエンス／ディープラーニングは普通、データのあるマシンで行います。ところが今、私たちは行いたいのは、学習計算をどこか**他のマシン**で実行したいという事です。具体的にいうと、データがローカルマシンに無い場合もあるという事です。\n",
    "\n",
    "そこで、Torchのtensorをかわりに、tensorへの**ポインタ**の使用を考えます。まずはコードを見てみましょう。最初に擬似的な外部マシンを所有する擬似的なユーザーを作成ます。ここではBobとします。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id=\"bob\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Bobのマシンはどこか別の惑星にでもあるものと仮定してください。 - 例えば火星とか！ですが、今のところマシンは空っぽです。\n",
    "まずは何かしらデータを準備しましょう。そのデータをBobに送ったり、Bobに送ったデータのポインタを参照したりしてみたいと思います。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = torch.tensor([1,1,1,1,1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "では - Bobにtensor（データ）を送ってみましょう。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr = x.send(bob)\n",
    "y_ptr = y.send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ジャジャーン！ 今、Bobは2つのtensor（データ）を持っています！ご自身ても確認してみてください。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x_ptr + x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一つ気が付くことはありませんでしたか？ `x.send(bob)`が実行されると私たちが`x_ptr`と名付けた新しいオブジェクトが帰ります。これは私たちの最初のtensorへの**ポインタ**です。ポインタは実際にはデータを持っていません。その代わりに別のマシンの実データであるTensorについてのメタデータを保持します。\n",
    "\n",
    "tensorへのポインタのことを以後**PointerTensor**と記載します。\n",
    "\n",
    "PointerTensorの目的は、リモートに存在するマシン上でTensorの計算処理を実行する際の、直感的なAPIを提供することです。では、ポインタが持っているメタデータを確認してみましょう。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "メタデータを確認しましょう。\n",
    "\n",
    "ポインタ特有の属性が2つ存在します。\n",
    "\n",
    "- `x_ptr.location : bob`, 場所, ポインタが参照している場所に関する情報です\n",
    "- `x_ptr.id_at_location : <random integer>`, Tensorが存在するマシン上でのIDです。\n",
    "\n",
    "Tensorの場所は右記の形式で、表現できます `<id_at_location>@<location>`\n",
    "\n",
    "もっと、一般的な属性もあります。\n",
    "- `x_ptr.id : <random integer>`, 私たちマシン上でのIDです。IDはランダムに生成されます。\n",
    "- `x_ptr.owner : \"me\"`, PointerTensorを所有するユーザーです。PySyftではワーカーと呼ばれます。ローカルマシンのワーカーは\"me\"です。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob == x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.id_at_location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ポインタの所有者も**Virtual**(擬似)ワーカーとなっていることが気になるかもしれません。そもそも私たちはローカルマシンのユーザーを作成してもいません。実を言うと、VirtualWorkerのBobと同様にデフォルトで私たち自身にもVirtualWorkerとしての割り当てがなされています。このワーカーは`hook = sy.TorchHook() `が実行された時に自動的に作られます。そのため、私たちが明示的につくる必要はありません。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me = sy.local_worker\n",
    "me"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me == x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最後になりますが、`.send()`でtensorを送った時と同じように`.get()`でtensorを自分たちのマシンに戻す事ができます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ご覧の通り、 Bobはもうtensorを持っていません。Bobが持っていたtensorは私たちのマシンに戻ってきています。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Section 1.2 - PointerTensorを使う\n",
    "\n",
    "TensorをBobへ送ったり、返してもらったりできるのは良いけど、こんなの全然ディープラーニングじゃない！私たちがやりたいことはリモートマシンでtensorの演算を実行することです。実をいうと、PointerTensorを使うと演算も簡単にできます。通常のtensorに対してやる事をPointerTensorに対して実行してやれば良いだけです。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5]).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1]).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x + y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ジャジャーン！\n",
    "\n",
    "この処理の裏では、実はとてもパワフルな事が行われています。xとyという2つのtensorをローカルマシンで加算するかわりに、加算コマンドがシリアライズされてBobに送られ、Bobのマシン上で演算を実行されることでzが作られ、zのポインタが私たちの元に戻ってきています。\n",
    "\n",
    "`.get()`を実行することで、演算結果を受け取ることもできるのです。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Torch 関数\n",
    "\n",
    "このAPI拡張はほとんど全てのTorchオペレーション（演算）に対してなされています！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = torch.add(x,y)\n",
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 変数 (バックプロパゲーション含む)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5.], requires_grad=True).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1.], requires_grad=True).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = (x + y).sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = x.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x.grad"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上記の通り、このAPIはとても柔軟性があり、リモートデータに対して、ほぼ全てのTorchのオペレーションを実行可能です。\n",
    "これによりFederated Learning, Secure Multi-Party Computation, DifferentialPrivacyのような、より高度なプライバシーに配慮したディープラーニングを実現するためのベースが提供されます!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# おめでとうございます！コミュニティに入ろう！\n",
    "\n",
    "本チュートリアルを完了しました。おめでとうございます！もし、このチュートリアルを気に入って、プライバシーに配慮した非中央集権的なAI技術や付随する（データやモデルの）サプライチェーンにご興味があって、プロジェクトに参加したいと思われるなら、以下の方法で可能です。\n",
    "\n",
    "### PySyftのGitHubレポジトリにスターをつける\n",
    "\n",
    "一番簡単に貢献できる方法はこのGitHubのレポジトリにスターを付けていただくことです。スターが増えると露出が増え、より多くのデベロッパーにこのクールな技術の事を知って貰えます。\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### Slackに入る\n",
    "\n",
    "最新の開発状況のトラッキングする一番良い方法はSlackに入ることです。\n",
    "下記フォームから入る事ができます。\n",
    "[http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### コードプロジェクトに参加する\n",
    "\n",
    "コミュニティに貢献する一番良い方法はソースコードのコントリビューターになることです。PySyftのGitHubへアクセスしてIssueのページを開き、\"Projects\"で検索してみてください。参加し得るプロジェクトの状況を把握することができます。また、\"good first issue\"とマークされているIssueを探す事でミニプロジェクトを探すこともできます。\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### 寄付\n",
    "\n",
    "もし、ソースコードで貢献できるほどの時間は取れないけど、是非何かサポートしたいという場合は、寄付をしていただくことも可能です。寄附金の全ては、ハッカソンやミートアップの開催といった、コミュニティ運営経費として利用されます。\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
